Skip to content

Apache2 mit php5 (mod_fcgid) und Suexec einrichten

Unser Ziel ist es, zwei Virtual Hosts mit unterschiedlichen Suexec-Usern zu erstellen, deren Home-Verzeichnis /home/<USERNAME>/htdocs, auch das DocumentRoot Verzeichnis ist. Die PHP-Prozessen laufen dann mit den Rechten des jeweiligen Users. Nennen wir die User in unserem Beispiel user1 und user2.

root:~# apt-get install apache2 apache2-utils apache2-suexec-custom libapache2-mod-fcgid php5-cgi

Mit dem Befehl a2enmod aktivieren wir die installierten Module.

root:~# a2enmod fcgid && a2enmod suexec

Nun bearbeiten wir die Konfigurationsdatei für das fcgid Module und tragen folgendes ein.

<IfModule mod_fcgid.c>
    # FcgidIdleTimeout n (300 seconds)
    # An idle fastcgi application will be terminated after IdleTimeout seconds.
    FcgidIdleTimeout 600

    # FcgidIdleScanInterval n (120 seconds)
    # The scan interval for idle fastcgi applications.
    FcgidIdleScanInterval 240

    # FcgidBusyTimeout n (300 seconds)
    # A fastcgi application will be terminated if handing a single request
    # longer than busy timeout.
    FcgidBusyTimeout 300

    # FcgidBusyScanInterval n (120 seconds)
    # The scan interval for busy timeout fastcgi applications.
    FcgidBusyScanInterval 120

    # FcgidErrorScanInterval n (3 seconds)
    # The scan interval for exit pending fastcgi applications. fastcgi
    # applications will be terminated within this scanning.
    FcgidErrorScanInterval 6

    # FcgidZombieScanInterval n (3 seconds)
    # The scan interval for zombie process.
    FcgidZombieScanInterval 6

    # FcgidProcessLifeTime n (3600 seconds)
    # A fastcgi application will be terminated if lifetime expired,
    # even no error is detected.
    FcgidProcessLifeTime 3600

    # FcgidIPCDir path (logs/fcgidsock)
    # The directory to put the UNIX domain socket. (UNIX only)
    # This directory should be writable only by apache user
    FcgidIPCDir /var/lib/apache2/fcgid/sock

    # FcgidProcessTableFile path (logs/fcgid_shm)
    # The share memory file path. (UNIX only) (version >= 2.1 only)
    FcgidProcessTableFile /var/lib/apache2/fcgid/shm

    # FcgidSpawnScoreUpLimit n (10)
    # The spawn-speed control score up water limit. Score increases while
    # a process is spawned or terminated, and decreases as time progresses;
    # while the score is higher than SpawnScoreUpLimit, the spawning will be
    # held for a while. The higher this number is, the higher speed of the
    # spawning can be.
    FcgidSpawnScoreUpLimit 150

    # FcgidSpawnScore n (1)
    # The weight of spawning. This weight will be plused to the spawn-control
    # score on every spawn. The higher this number is, the lower speed of
    # spawning can be.
    FcgidSpawnScore 1

    # FcgidTerminationScore n (2)
    # The weight of termination. This weight will be plused to the score while
    # fastcgi process terminates. The higher this number is, the lower speed
    # of spawning can be.
    FcgidTerminationScore 1

    # FcgidMaxProcesses n (1000)
    # The max count of total fastcgi process count.
    FcgidMaxProcesses 300

    # FcgidMaxProcessesPerClass n (100)
    # The maximum number of fastcgi application instances allowed to run for
    # particular one fastcgi application.
    FcgidMaxProcessesPerClass 10

    # FcgidMinProcessesPerClass n (3)
    # The minimum number of fastcgi application instances for any one fastcgi
    # application.
    # Idle fastcgi will not be killed if their count is less than n
    # Set this to 0, and tweak IdleTimeout
    FcgidMinProcessesPerClass 0

    # DefaultInitEnv env_name env_value
    # The default environment variables before a fastcgi application
    # is spawned. You can set this configuration more than once.

    # FcgidConnectTimeout n (3 seconds)
    # The connect timeout to a fastcgi application.
    FcgidConnectTimeout 600

    # FcgidIOTimeout n (20 seconds)
    # The communication timeout to a fastcgi application. Please increase this
    # value if your CGI have a slow initialization or slow respond.
    FcgidIOTimeout 120

    # OutputBufferSize n (64k bytes)
    # CGI output cache buffer size.
    FcgidOutputBufferSize 65536

    # PHP_Fix_Pathinfo_Enable n(n=0/1, default 0)
    # If you are using PHP and set cgi.fix_pathinfo=1 in php.ini, set PHP_Fix_Pathinfo_Enable 1.
    # From php.ini:
    # cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI. PHP's
    # previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok
    # what PATH_INFO is. For more information on PATH_INFO, see the cgi specs. Setting
    # this to 1 will cause PHP CGI to fix it's paths to conform to the spec. A setting
    # of zero causes PHP to behave as before. Default is zero. You should fix your scripts
    # to use SCRIPT_FILENAME rather than PATH_TRANSLATED.
    # cgi.fix_pathinfo=1
    FcgidFixPathinfo 1

    # FcgidMaxRequestsPerProcess n (0)
    # FastCGI application processes will be terminated after handling the specified number of requests.
    # A value of 0 disables the check.
    FcgidMaxRequestsPerProcess 10000

    # FcgidMaxRequestLen n (131072 bytes)
    # If the size of the request body exceeds this amount, the request will fail with
    # 500 Server Error. Administrators should change this to an appropriate value
    # for their site based on application requirements.
    FcgidMaxRequestLen 1024000000

    # FcgidMaxRequestInMem n (64k bytes)
    # This module reads the entire request body from the client before sending it to the application.
    # Normally the request body will be stored in memory. Once the amount of request body read
    # from the client exceeds FcgidMaxRequestInMem bytes, the remainder of the request body
    # will be stored in a temporary file.
    FcgidMaxRequestInMem 1024000000

    # Pass the Authorization to the script 
    FcgidPassHeader     Authorization

    <IfModule mod_mime.c>
        AddHandler fcgid-script .php
        AddHandler fcgid-script .fcgi
        AddType application/x-httpd-php .php
        AddType application/x-httpd-php-source .phps
    </IfModule>
    <Files ".user.ini"> 
        Require all denied
    </Files>
</IfModule>

# vim: syntax=apache ts=4 sw=4 sts=4 sr noet

Die Konfigurationsdatei für suexec finden wir unter /etc/apache2/suexec/ und hat den Namen des Users, unter dem der Apacheprozess läuft. Auf Debian Systemen ist das der User www-data. In der Datei /etc/apache2/suexec/www-data ändern wir den Eintrag in der ersten Zeile. Dieser lautet meist /var/www und ist das docroot Verzeichnis für den Apache. Da die Homeverzeichnisse der Unixusers unter /home/<USERNAME>/htdocs liegen und wir diese als DocumentRoot definieren wollen, tragen wir /home ein, da der php5-cgi Interpreter (den wir noch anlegen werden) innerhalb vom docroot liegen muss, da sonst suexec sich beschwert.

/home
public_html/cgi-bin
# The first two lines contain the suexec document root and the suexec userdir
# suffix. Both features can be disabled separately by prepending a # character.
# This config file is only used by the apache2-suexec-custom package.

Nun erstellen wir in den Homeverzeichnissen der Unixuser die Verzeichnisse bin/fcgid, var/tmp und htdocs.

root:~# mkdir -p /home/{user1,user2}/bin/fcgid
root:~# mkdir -p /home/{user1,user2}/var/tmp
root:~# mkdir -p /home/{user1,user2}/htdocs
root:~# chown -R user1.user1 /home/user1/htdocs
root:~# chown -R user1.user1 /home/user1/var/tmp
root:~# chown -R user1.user1 /home/user1/bin/fcgid
root:~# chown -R user2.user2 /home/user2/htdocs
root:~# chown -R user2.user2 /home/user2/var/tmp
root:~# chown -R user2.user2 /home/user2/bin/fcgid

Im bin/fcgid Verzeichnis erstellen wir nun eine Datei php5-cgi.

#!/bin/sh
# Shell Script To Run PHP5 using mod_fastcgi under Apache 2.x

### Set PATH ###
PHPRC="/home/<UNIXUSER>/bin/fcgid"
PHP_FCGI_CHILDREN=4
PHP_FCGI_MAX_REQUESTS=1000
FCGI_SERVER_MAX_STDERR_LINE_LEN=2047
TMPDIR="/home/<UNIXUSER>/var/tmp"

### no editing below ###
export TMPDIR
export PHP_FCGI_CHILDREN
export PHP_FCGI_MAX_REQUESTS
export FCGI_SERVER_MAX_STDERR_LINE_LEN
exec /usr/bin/php5-cgi
Nun setzen wir auf die Datei php5-cgi das Ausführungs-Bit und setzen die Dateirechte zu gunsten des jeweiligen Users.

root:~# chmod 755 /home/user1/bin/fcgid/php5-cgi
root:~# chmod 755 /home/user2/bin/fcgid/php5-cgi
root:~# chown user1.user1 /home/user1/bin/fcgid/php5-cgi
root:~# chown user2.user2 /home/user2/bin/fcgid/php5-cgi

Dann kopieren wir uns die Original php.ini Datei in das jeweilige fcgid Verzeichnis des jeweiligen Users.

root:~# cp /etc/php5/cgi/php.ini /home/user1/bin/fcgid/php.ini
root:~# chown user1.user1 /home/user1/bin/fcgid/php.ini
root:~# cp /etc/php5/cgi/php.ini /home/user2/bin/fcgid/php.ini
root:~# chown user2.user2 /home/user2/bin/fcgid/php.ini

Die folgenden Variablen habe ich für jeden User geändert. Der String <UNIXUSER> ist ein Platzhalter für den jeweiligen User. Dort muss dann der User user1 bzw. user2 eingetragen werden.

....
post_max_size = 32M
....
upload_max_filesize = 32M
....
upload_tmp_dir = /home/<UNIXUSER>/var/tmp
....

Zum testen, erstellen wir im DocumentRoot Verzeichnis htdocs eines jeden Users eine index.php mit dem Inhalt der phpinfo() Funktion.

root:~# echo -e "<?php\nphpinfo();\n?>" >/home/{user1,user2}/htdocs/index.php
root:~# chown user1.user1 /home/user1/htdocs/index.php
root:~# chown user2.user2 /home/user2/htdocs/index.php

Als letztes erstellen wir eine VirtualHosts Datei für user1 und user2. Die VirtualHost Datei könnte wie folgt aussehen. Wichtig sind die Pfade zum DocumentRoot Verzeichnis /home/<USERNAME>/htdocs, und der Pfad zum php5-cgi Interpreter /home/<USERNAME>/bin/fcgid/php5-cgi.

<VirtualHost *:80>
        ServerAdmin postmaster@example.com
        ServerName user1.example.com
        ServerSignature Off

        SuexecUserGroup user1 user1

        DocumentRoot /home/user1/htdocs
        <Directory />
                Options FollowSymLinks
                AllowOverride None
        </Directory>
        <Directory /home/user1/htdocs>
                Options -Indexes FollowSymLinks MultiViews
                DirectoryIndex index.htm index.html index.php
                AllowOverride None
                Order allow,deny
                allow from all
        </Directory>

        # PHP settings - mod_fcgid.c
        <IfModule mod_fcgid.c>
                <Files ~ "\.php$">
                        FCGIWrapper /home/user1/bin/fcgid/php5-cgi .php
                        Options +ExecCGI
                </Files>
        </IfModule>

        CustomLog ${APACHE_LOG_DIR}/user1.example.com_acc.log mycommon env=!DONTLOG
        ErrorLog ${APACHE_LOG_DIR}/user1.example.com_err.log
        LogLevel warn

</VirtualHost>

Nun aktivieren wir die VirtualHost Dateien mit a2ensite <FILE> und starten den Apache Webserver neu.

root:~# a2ensite user1
root:~# a2ensite user2
root:~# systemctl restart apache2